/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2022. All rights reserved.
 *
 */

import cluster from 'cluster';
import fs from 'fs';
import path from 'path';
import process from 'process';
import * as util from 'util';

import { isWindows } from '@ohos/hvigor-common';

import { HookType } from '../../../common/const/hook-const.js';
import { nodeConfigPathInfo } from '../../../common/node-config-path-info.js';
import { HvigorCommonConst } from '../../common/options/common-const.js';
import { ModuleOpt } from '../../common/options/project-structure-opt.js';
import { addModuleDependency } from '../../daemon/cluster/watch-config-file.js';
import { hvigorConfigInit } from '../../external/core/hvigor-config.js';
import { Project } from '../../external/core/hvigor-core-node.js';
import { hvigorCore } from '../../external/core/hvigor-core.js';
import { hvigor } from '../../external/core/hvigor.js';
import { HvigorLogger } from '../../log/hvigor-log.js';
import { DurationEvent } from '../../metrics/event/duration-event.js';
import { exitIfNotExists } from '../../util/file-util.js';
import { formatTime } from '../../util/time-util.js';
import { ValidateUtil } from '../../util/validate-util.js';
import { ProjectCacheService } from '../cache/project-cache-service.js';
import { AnalyzeMode, coreParameter } from '../data/global-core-parameters.js';
import { globalData } from '../data/global-data.js';
import { setHvigorConfigFileTsRoot } from '../util/ts_check.js';
import { HvigorLifecycleHook } from './hook/hvigor-lifecycle-hook.js';
import { ModuleImpl } from './hvigor-node-impl/module-impl.js';
import { ProjectImpl } from './hvigor-node-impl/project-impl.js';

const propertiesAlias = 'prop';

const log = HvigorLogger.getLogger('hvigor-init');

/**
 * 初始化hvigor的数据模型
 *
 */
export async function init(durationEvent: DurationEvent): Promise<void> {
  const env = globalData.cliEnv;
  const commandEntryTasks = globalData.cliOpts._;

  // 获取生命周期hook的实例对象
  const lifecycleHook = HvigorLifecycleHook.getInstance();

  promptUpdateNode();
  hvigorCore.setExtraConfig(env.configProps.get(propertiesAlias));
  hvigorCore.setCommandEntryTasks(commandEntryTasks);

  const projectRoot = env.cwd;
  const project = new ProjectImpl(path.basename(projectRoot), projectRoot);
  nodeConfigPathInfo.initNodeConfigPath(project);
  lifecycleHook.clear();
  hvigorConfigInit(project);

  // 执行用户的hvigorconfig文件
  evaluateHvigorConfig();

  // 触发configEvaluated hook
  await lifecycleHook.runHook(HookType.configEvaluated, hvigor.getHvigorConfig(), durationEvent);

  hvigor
    .getHvigorConfig()
    .getRootNodeDescriptor()
    .getChildNode()
    ?.forEach((hvigorNodeDescroptor) => {
      ValidateUtil.validateModule(
        new (class implements ModuleOpt {
          name: string = hvigorNodeDescroptor.name;
          srcPath: string = hvigorNodeDescroptor.srcPath;
        })(),
      );
      const moduleImpl = new ModuleImpl(project, hvigorNodeDescroptor.name, path.resolve(projectRoot, hvigorNodeDescroptor.srcPath));
      exitIfNotExists(log, moduleImpl.getNodeDir(), 'modules', path.resolve(project.getNodeDir(), HvigorCommonConst.BUILD_PROFILE_FILE));
      hvigorNodeDescroptor.extraOptions.forEach((value, key) => {
        moduleImpl.addExtraOption(key, value);
      });
      project.addSubModule(moduleImpl);
    });

  hvigorCore.initRootProject(project);

  // 触发nodesInitialized hook
  await lifecycleHook.runHook(HookType.nodesInitialized, hvigor, durationEvent);
  log.debug(`Hvigor init with startParameters:${util.inspect(coreParameter.startParams)}`);

  // 没有关闭增量功能,则需要初始化CacheService用于增量检查
  coreParameter.startParams.incrementalExecution && initCacheService(project);
}

/**
 * 初始化Project CacheService,用于增量构建
 *
 * @param {Project} project
 */
function initCacheService(project: Project): void {
  const startTime = process.hrtime();
  ProjectCacheService.getInstance(project).initialize();
  const taskEndTime: [number, number] = process.hrtime(startTime);
  const realTime = formatTime(taskEndTime);
  log.debug(`Cache service initialization finished in ${realTime}`);
}

/**
 * verbose模式下，非windows平台环境，计时打点功能在低版本node上会造成显著性能开销，提示升级node版本
 */
function promptUpdateNode() {
  if (
    (coreParameter.startParams.analyze === AnalyzeMode.ADVANCED || coreParameter.startParams.analyze === AnalyzeMode.TRACE) &&
    !isWindows() &&
    process.version < 'v18.14.1'
  ) {
    log.warn('In advanced mode, to enhance performance, node version v18.14.1 or later is preferred.');
  }
}

function evaluateHvigorConfig() {
  const hvigorConfigFilePath = path.resolve(hvigor.getHvigorConfig().getRootNodeDescriptor().srcPath, HvigorCommonConst.HVIGOR_CONFIG_FILE_NAME);
  let hvigorConfigFileRealPath;
  for (const suffix of HvigorCommonConst.HVIGOR_CONFIG_FILE_NAME_SUFFIX) {
    hvigorConfigFileRealPath = `${hvigorConfigFilePath}${suffix}`;
    if (fs.existsSync(hvigorConfigFileRealPath)) {
      if (coreParameter.startParams.hvigorfileTypeCheck && hvigorConfigFileRealPath.endsWith('.ts')) {
        setHvigorConfigFileTsRoot(hvigorConfigFileRealPath);
      }

      // 服务化场景下需要清理hvigorconfig的读取缓存
      delete require.cache[require.resolve(hvigorConfigFileRealPath)];

      try {
        require(hvigorConfigFileRealPath);
        log.debug('hvigorconfig, required');
      } catch (e: any) {
        log.errorMessageExit(e.name, e.message);
      }

      if (cluster.isWorker) {
        // 保证只在cluster场景下去做解析hvigorfile文件依赖的事情
        addModuleDependency(hvigorConfigFileRealPath);
      }
    }
  }
}
